import * as THREE from 'three';
import {
  BufferGeometry,
  Camera,
  Color,
  Geometry,
  Material,
  MathUtils,
  Mesh,
  PerspectiveCamera,
  Texture,
  Vector3,
} from 'three';
import BaseThreeApp from '../BaseThreeApp';
import DebugInfo from '../DebugInfo';
import { VTKLoader } from 'three/examples/jsm/loaders/VTKLoader';
import _00Test from '../00Test/_00Test';

interface IView {
  x: number;
  y: number;
  width: number;
  height: number;
  background: Color;
  eye: Vector3;
  up: Vector3;
  fov: number;
  canera?: PerspectiveCamera;
}
const axesY = new Vector3(0, 1, 0);

class _10_1MultipleViews extends BaseThreeApp {
  public scene: THREE.Scene;
  public renderer: THREE.WebGLRenderer;
  public geos: (Geometry | BufferGeometry)[] = [];
  public mats: Material[] = [];
  public texs: Texture[] = [];
  public mesh: Mesh;

  public views: IView[] = [
    {
      x: 0,
      y: 0,
      width: 0.5,
      height: 1,
      background: new Color(0.3, 0.3, 0.5),
      eye: new Vector3(0, 0, 5),
      up: axesY,
      fov: 60,
    },
    {
      x: 0.5,
      y: 0.0,
      width: 0.5,
      height: 0.5,
      background: new Color(0.5, 0.3, 0.3),
      eye: new Vector3(0, 0, -5),
      up: axesY,
      fov: 45,
    },
    {
      x: 0.5,
      y: 0.5,
      width: 0.5,
      height: 0.5,
      background: new Color(0.3, 0.5, 0.3),
      eye: new Vector3(0, 5, 0),
      up: new Vector3(-1, 0, 0),
      fov: 30,
    },
  ];

  start() {
    this.scene = new THREE.Scene();
    const aspect = this.clientWidth / this.clientHeight;
    const taget = new Vector3();
    for (const view of this.views) {
      const camera = new PerspectiveCamera(
        view.fov,
        (aspect * view.width) / view.height,
        0.1,
        1000
      );
      camera.position.copy(view.eye);
      camera.up.copy(view.up);
      camera.lookAt(taget);
      view.canera = camera;
    }

    this.renderer = new THREE.WebGLRenderer({
      canvas: this.element,
    });

    const material = new THREE.MeshLambertMaterial({
      color: 0xffffff,
      side: THREE.DoubleSide,
    });
    this.mats.push(material);

    const loader = new VTKLoader();
    loader.load('models/bunny.vtk', (geo) => {
      this.geos.push(geo);
      geo.computeVertexNormals();
      geo.center();
      const mesh = new THREE.Mesh(geo, material);
      this.mesh = mesh;
      mesh.scale.set(10, 10, 10);
      this.scene.add(mesh);
    });

    this.renderer.setDrawingBufferSize(this.clientWidth, this.clientHeight, 1);

    const ambient = new THREE.AmbientLight(0xffffff, 0.2);
    this.scene.add(ambient);

    const light = new THREE.DirectionalLight(0xffffff, 0.7);
    light.position.set(0, 0, 10);
    this.scene.add(light);

    const light2 = new THREE.DirectionalLight(0xffffff, 0.3);
    light2.position.set(0, 10, -10);
    this.scene.add(light2);

    this.isRunning = true;

    const animate = (time) => {
      if (!this.isRunning || this.element === null) {
        return;
      }
      const angel = (time / 1000) % 360;
      DebugInfo.Instance.begin();
      if (this.mesh) {
        this.mesh.setRotationFromAxisAngle(
          axesY,
          MathUtils.degToRad(angel * 10)
        );
      }
      const winWidth = this.clientWidth;
      const winHeigth = this.clientHeight;
      for (const view of this.views) {
        const x = Math.floor(winWidth * view.x);
        const y = Math.floor(winHeigth * view.y);
        const width = Math.floor(winWidth * view.width);
        const height = Math.floor(winHeigth * view.height);

        this.renderer.setViewport(x, y, width, height);
        this.renderer.setScissor(x, y, width, height);
        this.renderer.setScissorTest(true);
        this.renderer.setClearColor(view.background);

        this.renderer.render(this.scene, view.canera);
      }
      DebugInfo.Instance.end();
      requestAnimationFrame(animate);
    };
    animate(0);
  }

  public oncontextmenu(e: MouseEvent): any | void {
    e.preventDefault();
    return false;
  }

  onresize(e: UIEvent) {
    super.onresize(e);
    console.log('onresive');
    if (this.renderer) {
      this.renderer.setDrawingBufferSize(
        this.clientWidth,
        this.clientHeight,
        1
      );
      const aspect = this.clientWidth / this.clientHeight;
      for (const view of this.views) {
        if (view.canera) {
          view.canera.aspect = (aspect * view.width) / view.height;
          view.canera.updateProjectionMatrix();
        }
      }
    }
  }

  destory() {
    this.geos.forEach((v) => v.dispose());
    this.geos = [];
    this.mats.forEach((v) => v.dispose());
    this.mats = [];
    this.texs.forEach((v) => v.dispose());
    this.texs = [];
    super.destory();
  }
}

export default new _10_1MultipleViews();
